/*
日志器模块
1.抽象日志器基类
2.派生 同步日志器 异步日志器

*/
#ifndef __LOG_M__
#define __LOG_M__
#include "util.hpp"
#include "level.hpp"
#include "format.hpp"
#include "sink.hpp"
#include <atomic>
#include <mutex>
#include <cstdarg>
#include"looper.hpp"
#include<unordered_map>
namespace viclog
{
    class Logger
    {
    public:
        using ptr = std::shared_ptr<Logger>;

        Logger(const std::string &logger_name, LogLevel::value level, Formatter::ptr &formatter, std::vector<LogSink::ptr> sinks)
            : _logger_name(logger_name), _limit_level(level), _formatter(formatter), _sinks(sinks)
        {}
        const std::string& name()
        {
            return _logger_name;
        }
        // 以下接口完成日志消息对象构造构成并进行格式化，得到格式化后的日志消息字符串--落地输出
        void debug(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            // 通过传入的参数构造消息对象,进行日志消息格式化
            // 1.判断是否达到输出等级
            if (LogLevel::value::DEBUG < _limit_level)
            {
                return;
            }
            // 2.对fmt格式化字符和不定参进行字符串组织，得到日志消息的字符串
            va_list ap;
            va_start(ap, fmt);
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1)
            {
                std::cout << "vasprintf fail?\n";
                return;
            }
            va_end(ap);
            // 3.构造LogMsg对象

            // 4.通过格式化工具对LogMsg进行格式化，得到格式化后的字符串

            // 5.日志落地
            serialize(LogLevel::value::DEBUG, file, line, res);

            free(res);
        }
        void info(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            // 通过传入的参数构造消息对象,进行日志消息格式化
            // 1.判断是否达到输出等级
            if (LogLevel::value::INFO < _limit_level)
            {
                return;
            }
            // 2.对fmt格式化字符和不定参进行字符串组织，得到日志消息的字符串
            va_list ap;
            va_start(ap, fmt);
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1)
            {
                std::cout << "vasprintf fail?\n";
                return;
            }
            va_end(ap);
            // 3.构造LogMsg对象

            // 4.通过格式化工具对LogMsg进行格式化，得到格式化后的字符串

            // 5.日志落地
            serialize(LogLevel::value::INFO, file, line, res);

            free(res);
        }
        void warn(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            // 通过传入的参数构造消息对象,进行日志消息格式化
            // 1.判断是否达到输出等级
            if (LogLevel::value::WARN < _limit_level)
            {
                return;
            }
            // 2.对fmt格式化字符和不定参进行字符串组织，得到日志消息的字符串
            va_list ap;
            va_start(ap, fmt);
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1)
            {
                std::cout << "vasprintf fail?\n";
                return;
            }
            va_end(ap);
            // 3.构造LogMsg对象

            // 4.通过格式化工具对LogMsg进行格式化，得到格式化后的字符串

            // 5.日志落地
            serialize(LogLevel::value::WARN, file, line, res);

            free(res);
        }
        void error(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            // 通过传入的参数构造消息对象,进行日志消息格式化
            // 1.判断是否达到输出等级
            if (LogLevel::value::ERROR < _limit_level)
            {
                return;
            }
            // 2.对fmt格式化字符和不定参进行字符串组织，得到日志消息的字符串
            va_list ap;
            va_start(ap, fmt);
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1)
            {
                std::cout << "vasprintf fail?\n";
                return;
            }
            va_end(ap);
            // 3.构造LogMsg对象

            // 4.通过格式化工具对LogMsg进行格式化，得到格式化后的字符串

            // 5.日志落地
            serialize(LogLevel::value::ERROR, file, line, res);

            free(res);
        }
        void fatal(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            // 通过传入的参数构造消息对象,进行日志消息格式化
            // 1.判断是否达到输出等级
            if (LogLevel::value::FATAL < _limit_level)
            {
                return;
            }
            // 2.对fmt格式化字符和不定参进行字符串组织，得到日志消息的字符串
            va_list ap;
            va_start(ap, fmt);
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1)
            {
                std::cout << "vasprintf fail?\n";
                return;
            }
            va_end(ap);
            // 3.构造LogMsg对象

            // 4.通过格式化工具对LogMsg进行格式化，得到格式化后的字符串

            // 5.日志落地
            serialize(LogLevel::value::FATAL, file, line, res);

            free(res);
        }

    protected:
        void serialize(LogLevel::value level, const std::string &file, size_t line, char *str)
        {
            // 3.构造LogMsg对象
            LogMsg msg(level, line, file, _logger_name, str);
            // 4.通过格式化工具对LogMsg进行格式化，得到格式化后的字符串
            std::stringstream ss;
            _formatter->format(ss, msg);
            // 5.日志落地
            log(ss.str().c_str(), ss.str().size());
        }
        // 抽象接口完成实际的落地
        virtual void log(const char *data, size_t len) = 0;

    protected:
        std::mutex _mutex;
        std::string _logger_name;
        std::atomic<LogLevel::value> _limit_level; // 原子变量
        Formatter::ptr _formatter;
        std::vector<LogSink::ptr> _sinks;
    };

    class SyncLogger : public Logger
    {
    public:
        SyncLogger(const std::string &logger_name, LogLevel::value level, Formatter::ptr &formatter, std::vector<LogSink::ptr>& sinks)
            : Logger(logger_name, level, formatter, sinks)
        {}

    protected:
        void log(const char *data, size_t len)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if (_sinks.empty())
                return;
            for (auto &sink : _sinks)
            {
                sink->log(data, len);
            }
        }
    };
    class AsyncLogger : public Logger
    {
    public:
        AsyncLogger(const std::string &logger_name, 
        LogLevel::value level, 
        Formatter::ptr &formatter, 
        std::vector<LogSink::ptr>& sinks,
        AsyncType looper_type): 
        Logger(logger_name, level, formatter, sinks),
        _looper(std::make_shared<AsyncLooper>(std::bind(&AsyncLogger::realLog,this,std::placeholders::_1),looper_type))
        {}

    protected:
        void log(const char *data, size_t len)
        {
            _looper->push(data,len);
        }
        void realLog(Buffer& buf)//实际落地函数将缓冲区数据落地
        {
            if (_sinks.empty())
                return;
            for (auto &sink : _sinks)
            {
                sink->log(buf.begin(), buf.readAbleSize());
            }
            
        }
    private:
        AsyncLooper::ptr _looper;
    };

    // 建造者模式
    // 用建造者模式来建造日志器 简化用户使用
    // 1.抽象日志建造者类(完成日志器所需零部件的构造&日志器的构造)
    // 2.将不同的日志器创建放到同一个建造者类中完成
    // 3.派生出具体的建造者类  局部日志器建造者& 全局日志器建造者、
    //局部日志器建造者
    enum class LoggerType
    {
        LOGGER_SYNC,
        LOGGER_ASYNC,

    };
    class LoggerBuilder
    {
    public:
        LoggerBuilder():
        _logger_type(LoggerType::LOGGER_SYNC),
        _limit_level(LogLevel::value::DEBUG),
        _looper_type(AsyncType::ASYNC_SAFE)
        {}
        void buildLoggerType(LoggerType type){ _logger_type=type;}
        void buildEnableUnSafeAsync(){ _looper_type=AsyncType::ASYNC_UNSAFE;}
        void buildLoggerName(const std::string &name){_logger_name=name;}
        void buildLoggerLevel(LogLevel::value level){_limit_level=level;}
        void buildFormatter(const std::string pattern="[%d{%H:%M:%S}][%t][%c][%f:%l][%p]%T%m%n")
        {
            _formatter=std::make_shared<Formatter>(pattern);
        }
        template <class SinkType, class... Args>
        void buildSink(Args &&...args)
        {
            LogSink::ptr psink=SinkFactory::create<SinkType>(std::forward<Args>(args)...);
            _sinks.push_back(psink);
        }

        virtual Logger::ptr build() = 0;

    protected:
        AsyncType _looper_type;
        LoggerType _logger_type;
        std::string _logger_name;
        std::atomic<LogLevel::value> _limit_level; // 原子变量
        Formatter::ptr _formatter;
        std::vector<LogSink::ptr> _sinks;
    };

    class LocalLoggerBuilder : public LoggerBuilder
    {
    public:
        Logger::ptr build()
        {
            assert(_logger_name.empty()==false);
            if(_formatter.get()==nullptr)
            {
                _formatter=std::make_shared<Formatter>();
            }
            if(_sinks.empty())
            {
                buildSink<StdoutSink>();
            }
            if(_logger_type==LoggerType::LOGGER_SYNC)
            {
                return std::make_shared<SyncLogger>(_logger_name,_limit_level,_formatter,_sinks);
            }
            else
            {
                return std::make_shared<AsyncLogger>(_logger_name,_limit_level,_formatter,_sinks,_looper_type);
            }

        }
    };

    class LoggerManager
    {
    public:
        static LoggerManager &getInstance()
        {
            //c++11针对静态局部变量，编译器在编译层面实现了线程安全
            //在静态局部变量没有构造完成前，其他线程进入会阻塞
            static LoggerManager eton;
            return eton;
        }
        void addLogger(Logger::ptr& logger) 
        {
            if (hasLogger(logger->name())) return;
            std::unique_lock<std::mutex> lock(_mutex);
            _loggers.insert(std::make_pair(logger->name(),logger));
        }
        bool hasLogger(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it=_loggers.find(name);
            if(it==_loggers.end())
            {
                return false;
            }
            return true;
        }
        Logger::ptr getLogger(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it=_loggers.find(name);
            if(it==_loggers.end())
            {
                return Logger::ptr();
            }
            return it->second;

        }
        Logger::ptr rootLogger()
        {
            return _root_logger;
        }

    private:
        LoggerManager() {
            std::unique_ptr<viclog::LoggerBuilder> builder(new viclog::LocalLoggerBuilder());
            builder->buildLoggerName("root");
            _root_logger=builder->build();
            _loggers.insert(std::make_pair("root",_root_logger));
        }

    private:
        std::mutex _mutex;
        Logger::ptr _root_logger;
        std::unordered_map<std::string,Logger::ptr> _loggers;
    };
    //全局日志器建造者
    //在局部日志器基础数添加一个功能：将日志器添加到单例对象中
     class GlobalLoggerBuilder : public LoggerBuilder
    {
    public:
        Logger::ptr build()
        {
            assert(_logger_name.empty()==false);
            if(_formatter.get()==nullptr)
            {
                _formatter=std::make_shared<Formatter>();
            }
            if(_sinks.empty())
            {
                buildSink<StdoutSink>();
            }
            Logger::ptr logger;
            if(_logger_type==LoggerType::LOGGER_SYNC)
            {
                logger =std::make_shared<SyncLogger>(_logger_name,_limit_level,_formatter,_sinks);
            }
            else
            {
                logger= std::make_shared<AsyncLogger>(_logger_name,_limit_level,_formatter,_sinks,_looper_type);
            }
            LoggerManager::getInstance().addLogger(logger);
            return logger;

        }
    };

}
#endif